home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / fax / src / faxd / FaxSend.c++ < prev    next >
C/C++ Source or Header  |  1994-08-01  |  23KB  |  659 lines

  1. /*    $Header: /usr/people/sam/fax/faxd/RCS/FaxSend.c++,v 1.96 1994/04/10 03:57:26 sam Rel $ */
  2. /*
  3.  * Copyright (c) 1990, 1991, 1992, 1993, 1994 Sam Leffler
  4.  * Copyright (c) 1991, 1992, 1993, 1994 Silicon Graphics, Inc.
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and 
  7.  * its documentation for any purpose is hereby granted without fee, provided
  8.  * that (i) the above copyright notices and this permission notice appear in
  9.  * all copies of the software and related documentation, and (ii) the names of
  10.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  11.  * publicity relating to the software without the specific, prior written
  12.  * permission of Sam Leffler and Silicon Graphics.
  13.  * 
  14.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  15.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  16.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  17.  * 
  18.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  19.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  20.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  21.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  22.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  23.  * OF THIS SOFTWARE.
  24.  */
  25. #include <osfcn.h>
  26. #include <stdio.h>
  27. #include <sys/stat.h>
  28.  
  29. #include <Dispatch/dispatcher.h>
  30.  
  31. #include "tiffio.h"
  32. #include "FaxServer.h"
  33. #include "FaxMachineInfo.h"
  34. #include "FaxRecvInfo.h"
  35. #include "UUCPLock.h"
  36. #include "faxServerApp.h"
  37. #include "t.30.h"
  38. #include "config.h"
  39.  
  40. /*
  41.  * FAX Server Transmission Protocol.
  42.  */
  43. void
  44. FaxServer::sendFax(FaxRequest& fax, FaxMachineInfo& clientInfo)
  45. {
  46.     assert(fax.files.length() != 0);
  47.     assert(fax.number != "");
  48.     assert(fax.sender != "");
  49.     assert(fax.files.length() == fax.ops.length());
  50.     npages = fax.npages;
  51.     if (modemLock->lock()) {
  52.     if (setupModem()) {
  53.         changeState(SENDING);
  54.         IOHandler* handler =
  55.         Dispatcher::instance().handler(modemFd, Dispatcher::ReadMask);
  56.         if (handler)
  57.         Dispatcher::instance().unlink(modemFd);
  58.         /*
  59.          * Prepare the job for transmission by analysing
  60.          * the page characteristics and determining whether
  61.          * or not the page transfer parameters will have
  62.          * to be renegotiated after the page is sent.  This
  63.          * is done before the call is placed because it can
  64.          * be slow and there can be timing problems if this
  65.          * is done during transmission.
  66.          */
  67.         fxStr emsg;
  68.         if (sendPrepareFax(fax, clientInfo, emsg)) {
  69.         /*
  70.          * Construct the phone number to dial by applying the
  71.          * dialing rules to the user-specified dialing string.
  72.          */
  73.         fxStr dial = prepareDialString(fax.number);
  74.         fxStr canon = canonicalizePhoneNumber(fax.number);
  75.         log = new FaxMachineLog(canon, logMode);
  76.         setServerStatus("Sending job %s to %s",
  77.             (char*) fax.jobid, (char*) fax.external);
  78.         sendFax(fax, clientInfo, dial);
  79.         delete log, log = NULL;
  80.         } else
  81.         sendFailed(fax, send_failed, emsg);
  82.         /*
  83.          * Because some modems are impossible to safely hangup in the
  84.          * event of a problem, we force a close on the device so that
  85.          * the modem will see DTR go down and (hopefully) clean up any
  86.          * bad state its in.  We then wait a couple of seconds before
  87.          * trying to setup the modem again so that it can have some
  88.          * time to settle.  We want a handle on the modem so that we
  89.          * can be prepared to answer incoming phone calls.
  90.          */
  91.         discardModem(TRUE);
  92.         changeState(MODEMWAIT, 5);
  93.     } else {
  94.         sendFailed(fax, send_retry, "Can not setup modem", 4*pollModemWait);
  95.         discardModem(TRUE);
  96.         changeState(MODEMWAIT, pollModemWait);
  97.     }
  98.     modemLock->unlock();
  99.     } else {
  100.     if (state != LOCKWAIT)
  101.         sendFailed(fax, send_retry,
  102.         "Can not lock modem device", 2*pollLockWait);
  103.     if (state != SENDING && state != ANSWERING)
  104.         changeState(LOCKWAIT, pollLockWait);
  105.     }
  106.     u_int pagesSent = npages - fax.npages;
  107.     fax.npages = npages;
  108.     app->notifySendDone(&fax,
  109.     pagesSent,
  110.     clientInfo.getCSI(),
  111.     atoi(Class2Params::bitRateNames[clientParams.br & 7]),
  112.     Class2Params::dataFormatNames[clientParams.df & 3]);
  113.     if (fax.status != send_retry)
  114.     clientInfo.setJobInProgress("");
  115. }
  116.  
  117. void
  118. FaxServer::sendFailed(FaxRequest& fax, FaxSendStatus stat, const char* notice, u_int tts)
  119. {
  120.     fax.status = stat;
  121.     fax.notice = notice;
  122.     /*
  123.      * When requeued for the default interval (requeueOther),
  124.      * don't adjust the time-to-send field so that the spooler
  125.      * will set it according to the default algorithm that 
  126.      * uses the command-line parameter and a random jitter.
  127.      */
  128.     if (tts != requeueOther)
  129.     fax.tts = time(0) + tts;
  130.     traceStatus(FAXTRACE_SERVER, "SEND FAILED: %s", notice);
  131. }
  132.  
  133. /*
  134.  * Send the specified TIFF files to the FAX
  135.  * agent at the given phone number.
  136.  */
  137. void
  138. FaxServer::sendFax(FaxRequest& fax, FaxMachineInfo& clientInfo, const fxStr& number)
  139. {
  140.     int oTracingLevel = logTracingLevel;    // save default value
  141.     (void) clientInfo.getTracingLevel(logTracingLevel);
  142.     /*
  143.      * Check if this job includes a poll request, and
  144.      * if it does, inform the modem in case it needs to
  145.      * do something to get back status about whether or
  146.      * not documents are available for retrieval.
  147.      */
  148.     FaxSendOp op = send_poll;
  149.     if (fax.ops.find(op) != fx_invalidArrayIndex)
  150.     modem->requestToPoll();
  151.     fax.notice = "";
  152.     abortCall = FALSE;
  153.     clientInfo.setJobInProgress(fax.qfile);
  154.     CallStatus callstat = modem->dial(number);
  155.     if (callstat == FaxModem::OK && !abortRequested()) {
  156.     /*
  157.      * Call reached a fax machine.  Check remote's
  158.      * capabilities against those required by the
  159.      * job and setup for transmission.
  160.      */
  161.     fax.ndials = 0;
  162.     clientInfo.setCalledBefore(TRUE);
  163.     clientInfo.setDialFailures(0);
  164.     modem->sendBegin();
  165.     fxBool remoteHasDoc = FALSE;
  166.     fxStr notice;
  167.     u_int nsf;
  168.     fxStr csi;
  169.     if (!modem->getPrologue(clientCapabilities, nsf, csi, remoteHasDoc)) {
  170.         // NB: assume receiver is T.4 compatible...
  171.         sendFailed(fax, send_retry,
  172.     "Unable to get remote capabilities or remote is not T.4 compatible",
  173.         requeueOther);
  174.     } else {
  175.         clientInfo.setCSI(csi);            // record remote CSI
  176.         if (!sendClientCapabilitiesOK(clientInfo, nsf, notice)) {
  177.         // NB: mark job completed 'cuz there's no way recover
  178.         sendFailed(fax, send_failed, notice);
  179.         } else {
  180.         modem->sendSetupPhaseB();
  181.         /*
  182.          * Group 3 protocol forces any sends to precede any polling.
  183.          */
  184.         fax.status = send_done;            // be optimistic
  185.         op = send_tiff;
  186.         while (fax.ops.length() > 0) {        // send operations
  187.             u_int i = fax.ops.find(op);
  188.             if (i == fx_invalidArrayIndex)
  189.             break;
  190.             traceStatus(FAXTRACE_PROTOCOL, "SEND file \"%s\"",
  191.             (char*) fax.files[i]);
  192.             if (!sendFaxPhaseB(fax, clientInfo, fax.files[i])) {
  193.             /*
  194.              * On protocol errors retry more quickly
  195.              * (there's no reason to wait is there?).
  196.              */
  197.             if (fax.status == send_retry)
  198.                 fax.tts = time(0) + requeueProto;
  199.             break;
  200.             }
  201.             /*
  202.              * The file was delivered, notify the server.
  203.              * Note that a side effect of the notification
  204.              * is that this file is deleted from the set of
  205.              * files to send (so that it's not sent again
  206.              * if the job is requeued).  This is why we call
  207.              * find again at the top of the loop
  208.              */
  209.             app->notifyDocumentSent(fax, i);
  210.             fax.dirnum = 0;
  211.         }
  212.         if (fax.status == send_done && fax.ops.length() > 0)
  213.             sendPoll(fax, remoteHasDoc);
  214.         }
  215.     }
  216.     modem->sendEnd();
  217.     if (fax.status != send_done) {
  218.         clientInfo.setSendFailures(clientInfo.getSendFailures()+1);
  219.         clientInfo.setLastSendFailure(fax.notice);
  220.     } else
  221.         clientInfo.setSendFailures(0);
  222.     } else {
  223.     /*
  224.      * Analyze the call status codes and selectively decide if the
  225.      * job should be retried.  We try to avoid the situations where
  226.      * we might be calling the wrong number so that we don't end up
  227.      * harrassing someone w/ repeated calls.
  228.      */
  229.     fax.ndials++;
  230.     switch (callstat) {
  231.     case FaxModem::NOCARRIER:    // no carrier detected on remote side
  232.     case FaxModem::FAILURE:        // typically from dialing a data modem
  233.         /*
  234.          * Since some modems can not distinguish between ``No Carrier''
  235.          * and ``No Answer'' we offer this configurable hack whereby
  236.          * we'll retry the job <n> times in the face of ``No Carrier''
  237.          * dialing errors; if we've never previously reached a facsimile
  238.          * machine at that number.  This should not be used except if
  239.          * the modem is incapable of distinguishing betwee ``No Carrier''
  240.          * and ``No Answer''.
  241.          */
  242.         if (!clientInfo.getCalledBefore() && fax.ndials > noCarrierRetrys) {
  243.         sendFailed(fax, send_failed, FaxModem::callStatus[callstat]);
  244.         /*
  245.          * If the modem appears to distinguish ``No Carrier'' from
  246.          * ``No Answer'', then also reject future jobs to this number
  247.          * by setting up a rejection notice in the machine info
  248.          * database.
  249.          */
  250.         if (noCarrierRetrys <= 1)
  251.             clientInfo.setRejectNotice(FaxModem::callStatus[callstat]);
  252.         } else
  253.         sendFailed(fax, send_retry,
  254.             FaxModem::callStatus[callstat], requeueTTS[callstat]);
  255.         break;
  256.     case FaxModem::BUSY:        // busy signal
  257.     case FaxModem::NOANSWER:    // no answer or ring back
  258.     case FaxModem::NODIALTONE:    // no local dialtone, possibly unplugged
  259.     case FaxModem::ERROR:        // modem might just need to be reset
  260.         sendFailed(fax, send_retry,
  261.         FaxModem::callStatus[callstat], requeueTTS[callstat]);
  262.         break;
  263.     case FaxModem::OK:        // call was aborted by user
  264.         break;
  265.     }
  266.     if (callstat != FaxModem::OK) {
  267.         clientInfo.setDialFailures(clientInfo.getDialFailures()+1);
  268.         clientInfo.setLastDialFailure(fax.notice);
  269.     }
  270.     }
  271.     if (abortCall)
  272.     sendFailed(fax, send_failed, "Job aborted by user");
  273.     else if (fax.status == send_retry && ++fax.totdials == fax.maxdials) {
  274.     fxStr notice = fax.notice;
  275.     notice.append("; too many attempts to send");
  276.     sendFailed(fax, send_failed, notice);
  277.     }
  278.     modem->hangup();
  279.     /*
  280.      * Cleanup after the call.  If we have new information on
  281.      * the client's remote capabilities, the machine info
  282.      * database will be updated when the instance is destroyed.
  283.      */
  284.     logTracingLevel = oTracingLevel;    // restore default value
  285. }
  286.  
  287. /*
  288.  * Process a polling request.
  289.  */
  290. void
  291. FaxServer::sendPoll(FaxRequest& fax, fxBool remoteHasDoc)
  292. {
  293.     FaxSendOp op = send_poll;
  294.     u_int i = fax.ops.find(op);
  295.     if (i == fx_invalidArrayIndex) {
  296.     fax.notice = "polling operation not done because of internal failure";
  297.     traceStatus(FAXTRACE_SERVER, "internal muckup, lost polling request");
  298.     // NB: job is marked done
  299.     } else if (!remoteHasDoc) {
  300.     fax.notice = "remote has no document to poll";
  301.     traceStatus(FAXTRACE_SERVER, "REJECT: " | fax.notice);
  302.     // override to force status about polling failure
  303.     if (fax.notify == FaxRequest::no_notice)
  304.         fax.notify = FaxRequest::when_done;
  305.     } else {
  306.     fxStr cig = canonicalizePhoneNumber(fax.files[i]);
  307.     if (cig == "")
  308.         cig = canonicalizePhoneNumber(FAXNumber);
  309.     traceStatus(FAXTRACE_PROTOCOL, "POLL with CIG \"%s\"", (char*) cig);
  310.     FaxRecvInfoArray docs;
  311.     fax.status =
  312.         (pollFaxPhaseB(cig, docs, fax.notice) ? send_done : send_retry);
  313.     for (u_int j = 0; j < docs.length(); j++) {
  314.         const FaxRecvInfo& ri = docs[j];
  315.         if (ri.npages > 0) {
  316.         (void) chmod((char*) ri.qfile, recvFileMode);
  317.         app->notifyPollRecvd(fax, ri);
  318.         } else {
  319.         traceStatus(FAXTRACE_SERVER, "POLL: empty file \"%s\" deleted",
  320.             (char*) ri.qfile);
  321.         unlink((char*) ri.qfile);
  322.         }
  323.     }
  324.     if (fax.status == send_done)
  325.         app->notifyPollDone(fax, i);
  326.     }
  327. }
  328.  
  329. /*
  330.  * Phase B of Group 3 protocol.
  331.  */
  332. fxBool
  333. FaxServer::sendFaxPhaseB(FaxRequest& fax, FaxMachineInfo& clientInfo, const fxStr& file)
  334. {
  335.     fxBool status = FALSE;
  336.     TIFF* tif = TIFFOpen(file, "r");
  337.     if (tif && (fax.dirnum == 0 || TIFFSetDirectory(tif, fax.dirnum))) {
  338.     // set up DCS according to file characteristics
  339.     if (sendSetupParams(tif, clientParams, clientInfo, fax.notice)) {
  340.         /*
  341.          * Count pages sent and advance dirnum so that if we
  342.          * terminate prematurely we'll only transmit what's left
  343.          * in the current document/file.  Also, if nothing is
  344.          * sent, bump the counter on the number of times we've
  345.          * attempted to send the current page.  We don't try
  346.          * more than 3 times--to avoid looping.
  347.          */
  348.         u_int prevPages = npages;
  349.         status = modem->sendPhaseB(tif, clientParams, clientInfo,
  350.         fax.pagehandling, fax.notice);
  351.         if (!status)
  352.         fax.status = send_retry;
  353.         if (npages == prevPages) {
  354.         fax.ntries++;
  355.         if (fax.ntries > 2) {
  356.             if (fax.notice != "")
  357.             fax.notice.append("; ");
  358.             fax.notice.append(
  359.             "Giving up after 3 attempts to send same page");
  360.             traceStatus(FAXTRACE_SERVER, "SEND: %s \"%s\", dirnum %d",
  361.             (char*) fax.notice, (char*) file, fax.dirnum);
  362.             fax.status = send_failed;
  363.         }
  364.         } else {
  365.         fax.dirnum += npages - prevPages;
  366.         fax.ntries = 0;
  367.         }
  368.     } else
  369.         fax.status = send_failed;
  370.     } else {
  371.     fax.notice = tif ? "Can not set directory in document file" :
  372.                "Can not open document file";
  373.     traceStatus(FAXTRACE_SERVER, "SEND: %s \"%s\", dirnum %d",
  374.         (char*) fax.notice, (char*) file, fax.dirnum);
  375.     fax.status = send_failed;
  376.     }
  377.     if (tif)
  378.     TIFFClose(tif);
  379.     return (status);
  380. }
  381.  
  382. /*
  383.  * Check client's capabilities (DIS) against those of the
  384.  * modem and select the parameters that are best for us.
  385.  */
  386. fxBool
  387. FaxServer::sendClientCapabilitiesOK(FaxMachineInfo& clientInfo, u_int nsf, fxStr& emsg)
  388. {
  389.     /*
  390.      * Select signalling rate and minimum scanline time
  391.      * for the duration of the session.  These are not
  392.      * changed once they are set here.
  393.      */
  394.     clientInfo.setMaxSignallingRate(clientCapabilities.br);
  395.     int signallingRate =
  396.     modem->selectSignallingRate(clientInfo.getMaxSignallingRate());
  397.     if (signallingRate == -1) {
  398.     emsg = "Modem does not support negotiated signalling rate";
  399.     return (FALSE);
  400.     }
  401.     clientParams.br = signallingRate;
  402.  
  403.     clientInfo.setMinScanlineTime(clientCapabilities.st);
  404.     int minScanlineTime =
  405.     modem->selectScanlineTime(clientInfo.getMinScanlineTime());
  406.     if (minScanlineTime == -1) {
  407.     emsg = "Modem does not support negotiated min scanline time";
  408.     return (FALSE);
  409.     }
  410.     clientParams.st = minScanlineTime;
  411.  
  412.     clientParams.ec = EC_DISABLE;        // XXX
  413.     clientParams.bf = BF_DISABLE;
  414.     /*
  415.      * Record the remote machine's capabilities for use below in
  416.      * selecting tranfer parameters for each page sent.  The info
  417.      * constructed here is also recorded in a private database for
  418.      * use in pre-formatting documents sent in future conversations.
  419.      */
  420.     clientInfo.setSupportsHighRes(clientCapabilities.vr == VR_FINE);
  421.     clientInfo.setSupports2DEncoding(clientCapabilities.df >= DF_2DMR);
  422.     clientInfo.setMaxPageWidth(pageWidthCodes[clientCapabilities.wd]);
  423.     clientInfo.setMaxPageLength(pageLengthCodes[clientCapabilities.ln]);
  424.     if (nsf) {
  425.     // XXX add Adobe's PostScript protocol
  426.     traceStatus(FAXTRACE_PROTOCOL, "REMOTE NSF %#x", nsf);
  427.     }
  428.     traceStatus(FAXTRACE_PROTOCOL, "REMOTE best rate %s",
  429.     Class2Params::bitRateNames[clientCapabilities.br]);
  430.     traceStatus(FAXTRACE_PROTOCOL, "REMOTE max %s",
  431.     Class2Params::pageWidthNames[clientCapabilities.wd]);
  432.     traceStatus(FAXTRACE_PROTOCOL, "REMOTE max %s",
  433.     Class2Params::pageLengthNames[clientCapabilities.ln]);
  434.     traceStatus(FAXTRACE_PROTOCOL, "REMOTE best vres %s",
  435.     Class2Params::vresNames[clientCapabilities.vr]);
  436.     traceStatus(FAXTRACE_PROTOCOL, "REMOTE best format %s",
  437.     Class2Params::dataFormatNames[clientCapabilities.df]);
  438.     if (clientCapabilities.ec == EC_ENABLE)
  439.     traceStatus(FAXTRACE_PROTOCOL, "REMOTE supports error correction");
  440.     traceStatus(FAXTRACE_PROTOCOL, "REMOTE best %s",
  441.     Class2Params::scanlineTimeNames[clientCapabilities.st]);
  442.     traceStatus(FAXTRACE_PROTOCOL, "REMOTE %s PostScript transfer",
  443.     clientInfo.getSupportsPostScript() ? "supports" : "does not support");
  444.  
  445.     traceStatus(FAXTRACE_PROTOCOL, "USE %s",
  446.     Class2Params::bitRateNames[clientParams.br]);
  447.     traceStatus(FAXTRACE_PROTOCOL, "USE %s",
  448.     Class2Params::scanlineTimeNames[clientParams.st]);
  449.     return (TRUE);
  450. }
  451.  
  452. /*
  453.  * Prepare the job for transmission by analysing
  454.  * the page characteristics and determining whether
  455.  * or not the page transfer parameters will have
  456.  * to be renegotiated after the page is sent.  This
  457.  * is done before the call is placed because it can
  458.  * be slow and there can be timing problems if this
  459.  * is done during transmission.
  460.  */
  461. fxBool
  462. FaxServer::sendPrepareFax(FaxRequest& fax, FaxMachineInfo& clientInfo, fxStr& emsg)
  463. {
  464.     if (fax.pagehandling != "")        // already done
  465.     return (TRUE);
  466.     /*
  467.      * Scan the pages and figure out where session parameters
  468.      * will need to be renegotiated.  Construct a string of
  469.      * indicators to use when doing the actual transmission.
  470.      *
  471.      * NB: all files are coalesced into a single fax document
  472.      *     if possible
  473.      */
  474.     Class2Params params;        // current parameters
  475.     Class2Params next;            // parameters for next page
  476.     TIFF* tif = NULL;            // current open TIFF image
  477.     params.df = (u_int) -1;        // indicates first page
  478.     for (u_int i = 0;;) {
  479.     if (!tif || TIFFLastDirectory(tif)) {
  480.         /*
  481.          * Locate the next file to be sent.
  482.          */
  483.         if (tif)            // close previous file
  484.         TIFFClose(tif), tif = NULL;
  485.         if (i >= fax.ops.length())
  486.         goto done;
  487.         FaxSendOp op = send_tiff;
  488.         i = fax.ops.find(op, i);
  489.         if (i == fx_invalidArrayIndex)
  490.         goto done;
  491.         tif = TIFFOpen(fax.files[i], "r");
  492.         if (tif == NULL) {
  493.         emsg = "Can not open document file";
  494.         goto bad;
  495.         }
  496.         i++;            // advance for next find
  497.     } else {
  498.         /*
  499.          * Read the next TIFF directory.
  500.          */
  501.         if (!TIFFReadDirectory(tif)) {
  502.         emsg = "Problem reading document directory";
  503.         goto bad;
  504.         }
  505.     }
  506.     next = params;
  507.     if (!sendSetupParams1(tif, next, clientInfo, emsg))
  508.         goto bad;
  509.     if (params.df != (u_int) -1) {
  510.         /*
  511.          * The pagehandling string has:
  512.          * 'M' = EOM, for when parameters must be renegotiated
  513.          * 'S' = MPS, for when next page uses the same parameters
  514.          * 'P' = EOP, for the last page to be transmitted
  515.          */
  516.         fax.pagehandling.append(next == params ? 'S' : 'M');
  517.     }
  518.     params = next;
  519.     }
  520. done:
  521.     fax.pagehandling.append('P');        // EOP
  522.     return (TRUE);
  523. bad:
  524.     if (tif)
  525.     TIFFClose(tif);
  526.     return (FALSE);
  527. }
  528.  
  529. /*
  530.  * Select session parameters according to the info
  531.  * in the TIFF file.  We setup the encoding scheme,
  532.  * page width & length, and vertical-resolution
  533.  * parameters.  If the remote machine is incapable
  534.  * of handling the image, we bail out.
  535.  *
  536.  * Note that we shouldn't be rejecting too many files
  537.  * because we cache the capabilities of the remote machine
  538.  * and use this to image the facsimile.  This work is
  539.  * mainly done to optimize transmission and to reject
  540.  * anything that might sneak by.
  541.  */
  542. fxBool
  543. FaxServer::sendSetupParams1(TIFF* tif, Class2Params& params, FaxMachineInfo& clientInfo, fxStr& emsg)
  544. {
  545.     short compression;
  546.     (void) TIFFGetField(tif, TIFFTAG_COMPRESSION, &compression);
  547.     if (compression != COMPRESSION_CCITTFAX3) {
  548.     emsg = "Document is not in a Group 3-compatible format";
  549.     traceStatus(FAXTRACE_SERVER, "SEND: %s (file %s, compression %d)",
  550.         (char*) emsg, TIFFFileName(tif), compression);
  551.     return (FALSE);
  552.     }
  553.  
  554.     // XXX perhaps should verify samples and bits/sample???
  555.     long g3opts;
  556.     if (!TIFFGetField(tif, TIFFTAG_GROUP3OPTIONS, &g3opts))
  557.     g3opts = 0;
  558.     if (g3opts & GROUP3OPT_2DENCODING) {
  559.     if (!clientInfo.getSupports2DEncoding()) {
  560.         emsg = "Document was encoded with 2DMR,"
  561.            " but client does not support this data format";
  562.         traceStatus(FAXTRACE_SERVER, "REJECT: %s", (char*) emsg);
  563.         return (FALSE);
  564.     }
  565.     params.df = DF_2DMR;
  566.     } else
  567.     params.df = DF_1DMR;
  568.  
  569.     u_long w;
  570.     (void) TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
  571.     if (w > clientInfo.getMaxPageWidth()) {
  572.     emsg = "Client does not support document page width";
  573.     traceStatus(FAXTRACE_SERVER,
  574.         "REJECT: %s, max remote page width %u pixels"
  575.          ", image width %lu pixels",
  576.         (char*) emsg, clientInfo.getMaxPageWidth(), w);
  577.     return (FALSE);
  578.     }
  579.     // NB: only common values
  580.     params.wd = (w <= 1728 ? WD_1728 : w <= 2048 ? WD_2048 : WD_2432);
  581.  
  582.     /*
  583.      * Try to deduce the vertical resolution of the image
  584.      * image.  This can be problematical for arbitrary TIFF
  585.      * images 'cuz vendors sometimes don't give the units.
  586.      * We, however, can depend on the info in images that
  587.      * we generate 'cuz we're careful to include valid info.
  588.      */
  589.     float yres;
  590.     if (TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yres)) {
  591.     short resunit = RESUNIT_NONE;
  592.     (void) TIFFGetField(tif, TIFFTAG_RESOLUTIONUNIT, &resunit);
  593.     if (resunit == RESUNIT_INCH)
  594.         yres /= 25.4;
  595.     } else {
  596.     /*
  597.      * No vertical resolution is specified, try
  598.      * to deduce one from the image length.
  599.      */
  600.     u_long l;
  601.     TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &l);
  602.     yres = (l < 1450 ? 3.85 : 7.7);        // B4 at 98 lpi is ~1400 lines
  603.     }
  604.     if (yres >= 7.) {
  605.     if (!clientInfo.getSupportsHighRes()) {
  606.         emsg = "High resolution document is not supported by client";
  607.         traceStatus(FAXTRACE_SERVER,
  608.         "REJECT: %s, image resolution %g lines/mm",
  609.         (char*) emsg, yres);
  610.         return (FALSE);
  611.     }
  612.     params.vr = VR_FINE;
  613.     } else
  614.     params.vr = VR_NORMAL;
  615.  
  616.     /*
  617.      * Select page length according to the image size and
  618.      * vertical resolution.  Note that if the resolution
  619.      * info is bogus, we may select the wrong page size.
  620.      * Note also that we're a bit lenient in places here
  621.      * to take into account sloppy coding practice (e.g.
  622.      * using 200 dpi for high-res facsimile.
  623.      */
  624.     if (clientInfo.getMaxPageLength() != -1) {
  625.     u_long h = 0;
  626.     (void) TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
  627.     float len = h / yres;            // page length in mm
  628.     if (len > clientInfo.getMaxPageLength()) {
  629.         emsg = "Client does not support document page length";
  630.         traceStatus(FAXTRACE_SERVER,
  631.         "REJECT: %s, max remote page length %d mm"
  632.             ", image length %lu rows (%.2f mm)",
  633.         (char*) emsg, clientInfo.getMaxPageLength(), h, len);
  634.         return (FALSE);
  635.     }
  636.     // 330 is chosen 'cuz it's half way between A4 & B4 lengths
  637.     params.ln = (len < 330 ? LN_A4 : LN_B4);
  638.     } else
  639.     params.ln = LN_INF;
  640.     return (TRUE);
  641. }
  642.  
  643. fxBool
  644. FaxServer::sendSetupParams(TIFF* tif, Class2Params& params, FaxMachineInfo& clientInfo, fxStr& emsg)
  645. {
  646.     if (sendSetupParams1(tif, params, clientInfo, emsg)) {
  647.     traceStatus(FAXTRACE_PROTOCOL, "USE %s",
  648.         Class2Params::pageWidthNames[params.wd]);
  649.     traceStatus(FAXTRACE_PROTOCOL, "USE %s",
  650.         Class2Params::pageLengthNames[params.ln]);
  651.     traceStatus(FAXTRACE_PROTOCOL, "USE %s",
  652.         Class2Params::vresNames[params.vr]);
  653.     traceStatus(FAXTRACE_PROTOCOL, "USE %s",
  654.         Class2Params::dataFormatNames[params.df]);
  655.     return (TRUE);
  656.     } else
  657.     return (FALSE);
  658. }
  659.